from rhythms import Pattern
from events import SongEventList 

class PatternSequence( object ):
	def __init__(self):
		self.sequence = []
	def addPattern( self , patternname , numtimes= 1 ):
		self.sequence.append( (numtimes , patternname ))	

class Part( object ):
	def __init__(self):
		self.instruments = {}
		self.endtime = 0
	def __getitem__( self, instrument ):
		if not self.instruments.has_key( instrument ):
			self.instruments[ instrument ] = PatternSequence() 
		return self.instruments[ instrument ]	
	def render( self , starttime , songmanager , track ):
		for instrumentname in self.instruments:
			(instrument , timing , velocity ) = songmanager.getInstrument( instrumentname )
			patseq = self.instruments[ instrumentname ]
			curtime = starttime
			barlength = songmanager.getBarLength()
			for ( times , patternname ) in patseq.sequence:
				pattern = songmanager.getPattern( patternname )
				endtime = curtime + times * barlength
				pattern.renderPattern( track , instrument , curtime , endtime , barlength , velocity , timing )
				curtime = endtime 
				self.endtime = max( endtime , self.endtime )
			
			
		
class TrackManager( object ):
	def __init__(self , midichannel ):		
		self.midichannel =  midichannel 	
		self.parts = []
	def getChannel( self ):
		return self.midichannel
	def addPart( self , part , n =1  ):
	    for i in range( n ):
    		self.parts.append( part )
	def render( self , songmanager , track ):
		starttime = 0
		for part in self.parts:
			part.render( starttime , songmanager , track )
			starttime = part.endtime

class SongManager( object ):
	def __init__(self):		
		self.patterns = {}
		self.instruments = {}
		self.BPM = 120
		self.tracks = {}
	def setBPM( self , BPM ):
		self.BPM = BPM
	def getMidiTempo( self ):
		return int( 60000000 / self.BPM )
	def getBarLength( self ):
		return 60.0/self.BPM * 4

	def definePattern( self , name , pattern ):
		self.patterns[ name ] = Pattern( pattern )
	def getPattern( self , name ):
		if not self.patterns.has_key( name ):
			raise Exception, "No such patterns " + name 
		return self.patterns[ name ] 
	def defineInstrument( self , name , instrument , timing , velocity  ):
		self.instruments[ name ] = (  instrument , timing , velocity )
	def getInstrument( self , name ):
		if not self.instruments.has_key( name ):
			raise Exception, "No such Instrument " + name 
		return self.instruments[ name ] 
	def defineTrack( self , name , midichannel=0 ):
		self.tracks[ name ] = TrackManager( midichannel )
	def __getitem__( self, track ):
		if not self.tracks.has_key( track ):
			raise Exception, "No such track" 
		return self.tracks[ track ] 
	def run( self  ):
		song = SongEventList()
		song.setTempo( self.getMidiTempo() )
		for trackname in self.tracks:
			track = self.tracks[ trackname ]
			song[ trackname ].setChannel( track.getChannel() )
			track.render( self , song[ trackname ] )
		song.run( )
	
		
if __name__ == '__main__':
	pass
